﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
#if PLATFORM_ANDROID
using UnityEngine.Android;
#endif

namespace LuaFramework
{
    public class RecorderManager : Manager
    {
        public const int FREQUENCY = 8000;
        public const int MAX_RECORD_TIME = 5;
        public const int MAX_PLAY_TIME = 5;
        string drive = null;

        public bool IsRecording { private set; get; }

        AudioClip micClip;
        float[] micDataTemp;
        public short[] pcmDataList;
        public int recordPos;
        public float recordDuration;

        bool isSaveFirstHalf;
        void Awake() 
        {
           

            pcmDataList = new short[FREQUENCY * MAX_RECORD_TIME];
            micDataTemp = new float[FREQUENCY / 2];
            IsRecording = false;
        }

        public void BeginRecord()
        {
#if PLATFORM_ANDROID
            if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
            {
                Permission.RequestUserPermission(Permission.Microphone);
            }
#endif
           
            IsRecording = true;
            isSaveFirstHalf = true;
            recordPos = 0;
            recordDuration = 0;
            if (Microphone.devices.Length > 0)
                drive = Microphone.devices[0];
            micClip = Microphone.Start(drive, true, 1, FREQUENCY);
        }

        private new void Update()
        {
            if (IsRecording == false)
                return;

            recordDuration += Time.deltaTime;
            bool canWrite = false;
            if(isSaveFirstHalf)
            {
                int micPosition = Microphone.GetPosition(drive);
                if (micPosition > FREQUENCY / 2 && micPosition < FREQUENCY)
                {
                    micClip.GetData(micDataTemp, 0);
                    isSaveFirstHalf = !isSaveFirstHalf;
                    canWrite = true;
                }
            }
            else
            {
                int micPosition = Microphone.GetPosition(drive);
                if (micPosition > 0 && micPosition < FREQUENCY / 2)
                {
                    micClip.GetData(micDataTemp, FREQUENCY / 2);
                    isSaveFirstHalf = !isSaveFirstHalf;
                    canWrite = true;
                }
            }

            if(canWrite)
            {
                for (int i = 0; i < micDataTemp.Length; i++)
                {
                    if (recordPos >= pcmDataList.Length)
                        break;

                    short sample = 0;
                    int scaled = (int)(micDataTemp[i] * 32767.0f);
                    if (scaled < short.MinValue)
                        sample = short.MinValue;
                    else if (scaled > short.MaxValue)
                        sample = short.MaxValue;
                    else
                        sample = (short)scaled;
                    pcmDataList[recordPos] = sample;
                    recordPos++;
                }
            }
        }

        public float GetMaxValume()
        {
            float maxVolume = 1f;
            float[] volumeData = new float[120];
            int offset = Microphone.GetPosition(drive) - 120 + 1;

            if (offset < 0)
            {
                return 0;
            }

            bool flag = micClip.GetData(volumeData, offset);
            if (flag)
            {
                foreach (float item in volumeData)
                {
                    if (item > maxVolume)
                    {
                        maxVolume = item;
                    }
                }
            }
            else
            {
                Debug.LogError("Clip data get failed");
            }

            return maxVolume;
        }


        public void EndRecord()
        {
            IsRecording = false;
            Microphone.End(drive);
        }

        public bool isDriveWork()
        {
            if (drive != null)
                return true;
            else
                return false;
        }

        public static IEnumerator Encode(short[] pcmData, int len)
        {
            return AppFacade.threadManager.SetJob(() =>
            {
                byte[] output;
                int outputLen;
                if(OpencoreCodec.encode(pcmData, len, 4, out output, out outputLen))
                {
                    byte[] ret = new byte[outputLen];
                    Array.Copy(output, ret, outputLen);
                    return ret;
                }
                else
                {
                    return null;
                }
               
            });
        }

        public static IEnumerator Decode(byte[] amrData)
        {
            return AppFacade.threadManager.SetJob(() =>
            {
                short[] output;
                int outputLen;
                if (OpencoreCodec.decode(amrData, amrData.Length, out output, out outputLen))
                {
                    float[] ret = new float[outputLen];
                    for(int i = 0; i < outputLen; i++)
                    {
                        ret[i] = output[i] / (float)short.MaxValue;
                    }
                    return ret;
                }
                else
                {
                    return null;
                }

            });
        }
    }
}